// Ch9_1UI.cpp : Initialization functions

// CH9_1UI.cpp
// by Charles Mc Auley
// "Programming AutoCAD 2000 with ObjectARX"
//
// In this application we demonstrate how to use
// the AcTransactonManager, to contol our application.
// This application will respond to the user selecting
// Undo option as well as the user pressing the <Esc>
// key. If the user draws multiple windows by means of
// the while loop, the user can undo successive window
// drawing by means of the control mechanisms that the
// transaction manager provides. We also create a custom
// class derived from AcTransactionReactor and a custom
// class derived from AcApDocManagerReactor which allows
// to create an AcTransactionReactor for each document
// open.
//
/////////////////////////////////////////////////////////

#include "StdAfx.h"
#include "StdArx.h"
#include "resource.h"
#include "geassign.h"

HINSTANCE _hdllInstance =NULL ;

// Global pointer to our CMATransRact object.

CMADocReact *gpCMADocReact = NULL;


// This command registers an ARX command.
void AddCommand(const char* cmdGroup, const char* cmdInt, const char* cmdLoc,
				const int cmdFlags, const AcRxFunctionPtr cmdProc, const int idLocal = -1);

// NOTE: DO NOT edit the following lines.
//{{AFX_ARX_MSG
void InitApplication();
void UnloadApplication();
//}}AFX_ARX_MSG

// NOTE: DO NOT edit the following lines.
//{{AFX_ARX_ADDIN_FUNCS
//}}AFX_ARX_ADDIN_FUNCS

/////////////////////////////////////////////////////////////////////////////
// DLL Entry Point
extern "C"
BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID /*lpReserved*/)
{
	if (dwReason == DLL_PROCESS_ATTACH)
	{
        _hdllInstance = hInstance;
	} else if (dwReason == DLL_PROCESS_DETACH) {
	}
	return TRUE;    // ok
}



/////////////////////////////////////////////////////////////////////////////
// ObjectARX EntryPoint
extern "C" AcRx::AppRetCode 
acrxEntryPoint(AcRx::AppMsgCode msg, void* pkt)
{
	switch (msg) {
	case AcRx::kInitAppMsg:
		// Comment out the following line if your
		// application should be locked into memory
		acrxDynamicLinker->unlockApplication(pkt);
		acrxDynamicLinker->registerAppMDIAware(pkt);
		InitApplication();
		break;
	case AcRx::kUnloadAppMsg:
		UnloadApplication();
		break;
	}
	return AcRx::kRetOK;
}


// Init this application. Register your
// commands, reactors...
void InitApplication()
{
    AcApDocument* pDoc;
    AcApDocumentIterator* pDocIter;
	CMATransReact* pTrans;

	// NOTE: DO NOT edit the following lines.
	//{{AFX_ARX_INIT
	AddCommand("CMACH9_APPS", "WINDO", "WINDO", ACRX_CMD_MODAL, windo);
	AddCommand("CMACH9_APPS", "PWI", "PWI", ACRX_CMD_MODAL, pickWindowInfo);
	//}}AFX_ARX_INIT

	// TODO: add your initialization functions
	//acrxLoadModule("CMACh8_5.dbx", false, true);
	//acrxLoadModule("CMACh8_5.dbx", false, false);

	acutPrintf("Enter \"WINDO\" to execute the application.\n");
	acutPrintf("Enter \"PWI\" to retrieve the window properties. ");

	gpCMADocReact = new CMADocReact();

	pDocIter = acDocManager->newAcApDocumentIterator();

	for ( ; !pDocIter->done(); pDocIter->step())
	{
		pDoc = pDocIter->document();
		pTrans = new CMATransReact(true, pDoc);
	}

	delete pDocIter;
	
}

// Unload this application. Unregister all objects
// registered in InitApplication.
void UnloadApplication()
{
	// NOTE: DO NOT edit the following lines.
	//{{AFX_ARX_EXIT
	acedRegCmds->removeGroup("CMACH9_APPS");
	//}}AFX_ARX_EXIT

	acutPrintf("%s%s", "Goodbye\n", "Removing command group \"CMACH9_APPS\"\n");

	// TODO: clean up your application
	acrxUnloadModule("CMACh8_5.dbx", true);

	acDocManager->removeReactor(gpCMADocReact);

	if(gpCMADocReact != NULL)
	{
		delete gpCMADocReact;
	}
}

// This functions registers an ARX command.
// It can be used to read the localized command name
// from a string table stored in the resources.
void AddCommand(const char* cmdGroup, const char* cmdInt, const char* cmdLoc,
				const int cmdFlags, const AcRxFunctionPtr cmdProc, const int idLocal)
{
	char cmdLocRes[65];

	// If idLocal is not -1, it's treated as an ID for
	// a string stored in the resources.
	if (idLocal != -1) {

		// Load strings from the string table and register the command.
		::LoadString(_hdllInstance, idLocal, cmdLocRes, 64);
		acedRegCmds->addCommand(cmdGroup, cmdInt, cmdLocRes, cmdFlags, cmdProc);

	} else
		// idLocal is -1, so the 'hard coded'
		// localized function name is used.
		acedRegCmds->addCommand(cmdGroup, cmdInt, cmdLoc, cmdFlags, cmdProc);
}


// User defined functions called from Ch9_1UICommands.cpp
Acad::ErrorStatus appendToBlock(AcDbEntity *pEnt, AcDbObjectId& idEnt,
								const char *pcBlockName, AcDbDatabase *pDb)
{
	Acad::ErrorStatus es;
	AcDbBlockTable *pBlockTable = NULL;
	AcDbBlockTableRecord *pBlockTableRecord = NULL;

	// Default to current database
	if(!pDb)
		pDb = acdbHostApplicationServices()->workingDatabase();

	// Get block table
	if((es = pDb->getBlockTable( pBlockTable, AcDb::kForRead )) != Acad::eOk)
		return es;

    // Find block record
	if((es = pBlockTable->getAt(pcBlockName, pBlockTableRecord, AcDb::kForWrite )) != Acad::eOk)
	{
		pBlockTable->close();
		return es;
	}
    
	// append new entity to block:
    es = pBlockTableRecord->appendAcDbEntity( idEnt, pEnt );
	    
	pBlockTableRecord->close();
	pBlockTable->close();

	return es;
}


Adesk::Boolean getWindowInputParameters(CMARectWindow* pWindow)
{
	AcGePoint3d startPt;
	AcGePoint3d pickPt;
	int rows = 1, cols = 1;
	double windLength, windHeight;
	int rc;	// Return code

	acedInitGet(RSG_NONULL + RSG_NONEG + RSG_NOZERO, NULL);
	rc = acedGetReal("\nWindow Height: ", &windHeight);

	if(rc == RTCAN || rc == RTERROR)
	{
		return Adesk::kFalse;
	}

	acedInitGet(RSG_NONULL + RSG_NONEG + RSG_NOZERO, NULL);
	rc = acedGetReal("\nWindow Length: ", &windLength);

	if(rc == RTCAN || rc == RTERROR)
	{
		return Adesk::kFalse;
	}

	acedInitGet(RSG_NOZERO + RSG_NONEG, NULL);
	rc = acedGetInt("\nNumber of window columns <Return> for none: ", &cols);
	
	if(rc == RTCAN || rc == RTERROR)
	{
		return Adesk::kFalse;
	}

	acedInitGet(RSG_NOZERO + RSG_NONEG, NULL);
	rc = acedGetInt("\nNumber of window rows <Return> for none: ", &rows);
	
	if(rc == RTCAN || rc == RTERROR)
	{
		return Adesk::kFalse;
	}


	acedInitGet(NULL, NULL);
	rc = acedGetPoint(NULL, "\nPick lower left window insertion point <Return for (0,0)>: ", 
				asDblArray(pickPt));

	
	switch(rc)
	{
		case RTCAN:
		case RTERROR:
			return Adesk::kFalse;
		break;

		case RTNONE:
			startPt.x = 0;
			startPt.y = 0;
			startPt.z = 0;
		break;

		case RTNORM:
			startPt.x = pickPt.x;
			startPt.y = pickPt.y;
			startPt.z = pickPt.z;
		break;
	}

	// Fill out the window class object
	// with the input values

	pWindow->setWindowLength(windLength);
	pWindow->setWindowHeight(windHeight);
	pWindow->setWindowCols(cols);
	pWindow->setWindowRows(rows);
	pWindow->setWindowStartPoint(startPt);

	return Adesk::kTrue;
}

void draw_window()
{
	AcDbDatabase *pCurDb;
	AcDbObjectId windId;
	Acad::ErrorStatus es;
	AcTransaction *pTrans;

	CMARectWindow *pRectWindow;	// RectWindow class

	pCurDb = acdbHostApplicationServices()->workingDatabase();

	pTrans = actrTransactionManager->startTransaction();

    if (pTrans == NULL)
	{
        acutPrintf( "\nCan't start transaction!\n" );
        return;
    }

	pRectWindow = new CMARectWindow;
	
	if(!getWindowInputParameters(pRectWindow))
	{
		acutPrintf("\nError in window input parameters. ");
		if(pRectWindow != NULL)
		{
			delete pRectWindow;
		}
		actrTransactionManager->abortTransaction();
		return;
	}


	es = appendToBlock(pRectWindow, windId, ACDB_MODEL_SPACE, pCurDb);
	if(es != Acad::eOk)
	{
		acutPrintf("\nError drawing custom entity. ");
		if(pRectWindow)
		{
			delete pRectWindow;
		}
		actrTransactionManager->abortTransaction();
		return;
	}

	es = actrTransactionManager->addNewlyCreatedDBRObject(pRectWindow);
	if(es != Acad::eOk)
	{
		acutPrintf("\nError appending window enitity to AutoCAD database. ");
		if(pRectWindow)
		{
			delete pRectWindow;
		}
		actrTransactionManager->abortTransaction();
		return;
	}

	pRectWindow->close();
	pRectWindow->draw();

}
